package com.ics.cmsadmin.modules.sso.utils;

import com.ics.cmsadmin.modules.sso.LoginInfo;
import com.ics.cmsadmin.frame.utils.GsonUtils;
import com.ics.cmsadmin.frame.utils.RedisUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Optional;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 登陆相关静态方法
 * Created by 666666 on 2018/8/25.
 */
public final class SsoUtils {

    private static final Pattern loginTokenPattern = Pattern.compile("^(.*?):(.*?)$");
    private static final long LOGIN_TIME = 3600L;
    private static final String LOGIN_TOKEN = "LOGIN_TOKEN";
    private static final String LOGIN_USER_ID = "LOGIN_USER_ID";
    /**
     * 保存登陆信息到redis
     */
    public static final void saveLoginInfo2Redis(LoginTypeEnum loginTypeEnum, LoginInfo loginInfo) {
        loginInfo.setTimeoutTime(LOGIN_TIME);
        saveLoginInfo2Redis(loginTypeEnum, loginInfo, LOGIN_TIME);
    }

    /**
     * 保存登陆信息到redis
     */
    public static final void saveLoginInfo2Redis(LoginTypeEnum loginTypeEnum, LoginInfo loginInfo, long timeoutSeconds) {
        if (loginInfo == null || StringUtils.isBlank(loginInfo.getLoginId())) {
            return;
        }
        deleteLoginInfoFromRedis(loginInfo.getLoginId());
        String loginToken = loginTypeEnum.name() + ":" + UUID.randomUUID().toString();
        loginInfo.setLoginToken(loginToken);
        loginInfo.setTimeoutTime(timeoutSeconds);
        RedisUtils.set(loginToken, GsonUtils.toJson(loginInfo), timeoutSeconds);
        RedisUtils.set(String.format("%s:%s", LOGIN_USER_ID, loginInfo.getLoginId()), loginToken, timeoutSeconds);
    }
    /**
     * 根据登陆用户id删除登陆用户
     */
    public static final void deleteLoginInfoFromRedis(String loginUserId) {
        String loginUserToken = RedisUtils.get(String.format("%s:%s", LOGIN_USER_ID, loginUserId));
        if (StringUtils.isNotBlank(loginUserToken)){
            RedisUtils.delete(loginUserId);
            RedisUtils.delete(loginUserToken);
        }
    }

    /**
     * 从请求获取loginToken，
     * 之后从redis查询是否该用户的登陆信息
     */
    public  static LoginInfo getLoginUser(HttpServletRequest request) {
        String loginToken = request.getParameter(LOGIN_TOKEN);
        if (StringUtils.isNotBlank(loginToken)){
            return loadLoginInfoFromRedis(loginToken);
        }
        Cookie[] cookies = request.getCookies();
        if (cookies != null){
            Optional<Cookie> loginTokenCookie = Arrays.asList(cookies).stream()
                .filter(cookie -> StringUtils.equals(cookie.getName(), LOGIN_TOKEN))
                .findFirst();
            if (loginTokenCookie.isPresent()){
                return loadLoginInfoFromRedis(loginTokenCookie.get().getValue());
            }
        }
        return loadLoginInfoFromRedis(request.getHeader(LOGIN_TOKEN));
    }

    /**
     * 从redis获取用户信息
     * @param loginToken    登陆token
     * @return  用户信息
     */
    public static LoginInfo loadLoginInfoFromRedis(String loginToken){
        if (StringUtils.isBlank(loginToken)){
            return null;
        }
        Matcher matcher = loginTokenPattern.matcher(loginToken);
        if (! matcher.matches()){
            return null;
        }
        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOfType(matcher.group(1));
        if (loginTypeEnum == null){
            return null;
        }
        LoginInfo loginInfo = GsonUtils.fromJson2Bean(RedisUtils.get(loginToken), loginTypeEnum.getUserInfoClass());
        if (loginInfo != null){
            long timeoutTime = loginInfo.getTimeoutTime() > 0 ? loginInfo.getTimeoutTime() : LOGIN_TIME;
            RedisUtils.expire(loginToken, timeoutTime);
            RedisUtils.expire(String.format("%s:%s", LOGIN_USER_ID, loginInfo.getLoginId()), timeoutTime);
        }
        return loginInfo;
    }

    public  static final String getLoginUserId(HttpServletRequest request) {
        LoginInfo loginInfo = getLoginUser(request);
        if (loginInfo == null){
            return null;
        }
        return loginInfo.getLoginId();
    }
}
